package com.tbynet.jwp.admin;

import java.util.Map;

import com.jfinal.aop.Inject;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.StrKit;
import com.tbynet.jwp.framework.core.JwpInterceptor;
import com.tbynet.jwp.service.spi.UserManager;
import com.tbynet.jwp.model.Usermeta;
import com.tbynet.jwp.model.Users;
import com.tbynet.jwp.repository.spi.UserService;

/**
 * 管理员权限拦截器
 *
 * 核心职责：
 * 1. 用户身份验证和会话管理
 * 2. 管理员权限验证
 * 3. 用户信息加载和设置
 * 4. 访问控制和重定向处理
 *
 * 设计原则：
 * - 继承BaseInterceptor获得通用功能
 * - 专注于管理员特定的权限验证
 * - 清晰的错误处理和重定向
 * - 完善的日志记录
 *
 * @author 佰亿互联
 * @version 3.0
 * @since 2025-11-04
 */
public class AdminInterceptor extends JwpInterceptor implements Interceptor {

    // ========== 配置常量 ==========

    /** 管理员公开接口 */
    private static final String[] ADMIN_PUBLIC_INTERFACES = {
            "/admin/login",
            "/admin/captcha",
            "/admin/register",
            "/admin/forget",
            "/admin/clear"
    };

    /** 拦截器配置 */
    private final InterceptorConfig config = new InterceptorConfig()
            .setPublicInterfaces(ADMIN_PUBLIC_INTERFACES)
            .setLoginUrl("/admin/login")
            .setErrorPage("/admin/error.html");

    // ========== 依赖注入 ==========

    /** 用户管理编排层 - 用于用户验证和权限检查 */
    @Inject
    private UserManager userManager;

    /** 用户服务层 - 用于用户数据获取 */
    @Inject
    private UserService userService;

    // ========== 拦截器核心方法 ==========

    /**
     * 拦截器主方法
     *
     * 业务逻辑流程：
     * 1. 记录请求开始日志
     * 2. 检查是否为公开接口
     * 3. 用户身份验证和权限检查
     * 4. 加载用户信息和设置控制器属性
     * 5. 记录请求完成日志
     *
     * @param inv 拦截器调用对象
     */
    @Override
    public void intercept(Invocation inv) {
        long startTime = System.currentTimeMillis();

        try {
            // 1. 记录请求开始日志
            logRequestStart(inv, "AdminInterceptor");

            AdminController controller = (AdminController) inv.getController();
            String actionKey = inv.getActionKey();

            // 2. 检查是否为公开接口
            if (isPublicInterface(actionKey, config.getPublicInterfaces())) {
                log.debug("公开接口跳过权限验证，ActionKey: %s", actionKey);
                inv.invoke();
                return;
            }

            // 3. 用户身份验证和权限检查
            Users user = authenticateUser(controller, inv);
            if (user == null) {
                return; // 认证失败已处理重定向
            }

            // 4. 权限验证
            if (!validateAdminPermission(user, actionKey)) {
                return; // 权限验证失败已处理
            }

            // 5. 加载用户信息和设置控制器属性
            setupUserContext(controller, user, inv);

            // 执行后续拦截器或Action
            inv.invoke();

        } catch (Exception e) {
            handleInterceptorException(inv, e);
        } finally {
            // 6. 记录请求完成日志
            logRequestComplete(inv, "AdminInterceptor", startTime);
        }
    }

    // ========== 私有方法：用户认证 ==========

    /**
     * 用户身份认证
     *
     * @param controller 控制器对象
     * @param inv 拦截器调用对象
     * @return 认证成功的用户对象，认证失败返回null
     */
    private Users authenticateUser(AdminController controller, Invocation inv) {
        // 获取会话ID
        String sessionId = getSessionId(controller, Users.sessionIdName);

        // 验证会话有效性
        Users user = userManager.validateAndGetLoginUser(sessionId);

        if (user == null) {
            // 处理未认证请求
            handleUnauthenticated(controller, inv, config.getLoginUrl());
            return null;
        }

        log.debug("用户认证成功，用户ID: %s, ActionKey: %s",
                user.getID(), inv.getActionKey());

        return user;
    }

    /**
     * 验证管理员权限
     *
     * @param user 用户对象
     * @param actionKey 操作键
     * @return 是否具有管理员权限
     */
    private boolean validateAdminPermission(Users user, String actionKey) {
        long startTime = System.currentTimeMillis();

        try {
            // 获取用户权限信息
            Usermeta permissions = userService.getUserMeta(user.getID(), "permissions");
            if (permissions == null) {
                log.warn("用户权限信息不存在，用户ID: %s", user.getID());
                return false;
            }

            // 解析权限信息
            @SuppressWarnings("unchecked")
            Map<String, Boolean> permissionMap = (Map<String, Boolean>) permissions.getPermissions().toLinkedHashMap();

            // 检查管理员权限
            boolean hasPermission = permissionMap != null && !permissionMap.isEmpty() &&
                    permissionMap.containsKey("activate_plugins");

            log.debug("管理员权限检查完成，用户ID: %s, 结果: %s, 耗时: %sms",
                    user.getID(), hasPermission, System.currentTimeMillis() - startTime);

            // 记录权限事件
            logPermissionEvent("ADMIN_PERMISSION_CHECK", user.getID(), actionKey,
                    "admin_access", hasPermission ? "GRANTED" : "DENIED");

            return hasPermission;

        } catch (Exception e) {
            log.error("检查管理员权限异常，用户ID: %s", user.getID(), e);
            return false;
        }
    }

    // ========== 私有方法：用户上下文设置 ==========

    /**
     * 设置用户上下文
     *
     * @param controller 控制器对象
     * @param user 用户对象
     * @param inv 拦截器调用对象
     */
    private void setupUserContext(AdminController controller, Users user, Invocation inv) {
        // 加载用户附加信息
        loadUserAdditionalInfo(user);

        // 设置控制器属性
        setControllerAttributes(controller, user, inv);

        log.debug("用户上下文设置完成，用户ID: %s, ActionKey: %s",
                user.getID(), inv.getActionKey());
    }

    /**
     * 加载用户附加信息
     *
     * @param user 用户对象
     */
    private void loadUserAdditionalInfo(Users user) {
        long startTime = System.currentTimeMillis();

        try {
            // 加载用户头像
            Usermeta avatarMeta = userService.getUserMeta(user.getID(), Usermeta.simple_local_avatar);
            if (avatarMeta != null) {
                user.put(Usermeta.simple_local_avatar, avatarMeta.getMetaValue());
            }

            // 加载用户基本信息
            loadUserBasicInfo(user);

            log.debug("用户附加信息加载完成，用户ID: %s, 耗时: %sms",
                    user.getID(), System.currentTimeMillis() - startTime);

        } catch (Exception e) {
            log.error("加载用户附加信息异常，用户ID: %s", user.getID(), e);
        }
    }

    /**
     * 加载用户基本信息
     *
     * @param user 用户对象
     */
    private void loadUserBasicInfo(Users user) {
        try {
            // 加载用户显示名称
            Usermeta displayNameMeta = userService.getUserMeta(user.getID(), "display_name");
            if (displayNameMeta != null && StrKit.notBlank(displayNameMeta.getMetaValue())) {
                user.put("display_name", displayNameMeta.getMetaValue());
            }

            // 加载用户角色信息
            Usermeta roleMeta = userService.getUserMeta(user.getID(), Usermeta.role);
            if (roleMeta != null) {
                user.put(Usermeta.role, roleMeta.getMetaValue());
            }

        } catch (Exception e) {
            log.warn("加载用户基本信息异常，用户ID: %s", user.getID(), e);
        }
    }

    /**
     * 设置控制器属性
     *
     * @param controller 控制器对象
     * @param user 用户对象
     * @param inv 拦截器调用对象
     */
    private void setControllerAttributes(AdminController controller, Users user, Invocation inv) {
        // 设置登录用户信息
        controller.set(Users.loginUserCacheName, user);

        // 设置ActionKey用于页面显示
        controller.set("ACTION_KEY", inv.getActionKey());

        // 设置当前用户ID
        controller.set("currentUserId", user.getID());

        // 设置用户显示名称
        String displayName = (String) user.get("display_name");
        if (StrKit.isBlank(displayName)) {
            displayName = user.getUserLogin();
        }
        controller.set("currentUserName", displayName);

        // 设置用户角色
        String role = (String) user.get(Usermeta.role);
        controller.set("currentUserRole", role);
    }

    // ========== 私有方法：异常处理 ==========

    /**
     * 处理拦截器异常
     *
     * @param inv 拦截器调用对象
     * @param e 异常对象
     */
    private void handleInterceptorException(Invocation inv, Exception e) {
        AdminController controller = (AdminController) inv.getController();
        handleSystemException(controller, inv, e, config.getErrorPage());
    }

    // ========== 重写基础方法 ==========

    /**
     * 处理权限拒绝（重写基础方法）
     */
    @Override
    protected void handlePermissionDenied(Controller controller, Invocation inv,
                                          Object user, String errorPage) {
        String userId = user != null ? String.valueOf(user) : "unknown";
        String actionKey = inv.getActionKey();
        String clientIp = getClientIp(inv);

        log.warn("管理员权限拒绝，用户ID: %s, ActionKey: %s, IP: %s",
                userId, actionKey, clientIp);

        // 设置错误信息
        controller.set("error", "permission");
        controller.set("errorMessage", "您没有管理员权限访问该页面");
        controller.set("errorCode", 403);

        // 使用配置的错误页面
        controller.render(config.getErrorPage());

        // 记录安全事件
        logSecurityEvent("ADMIN_PERMISSION_DENIED", userId, actionKey, clientIp,
                "管理员权限拒绝，访问资源: " + actionKey);
    }
}